package com.wanwu.channel.service.strategy;

import com.alibaba.fastjson.JSONObject;
import com.wanwu.channel.common.enums.ExceptionEnum;
import com.wanwu.channel.common.enums.PayType;
import com.wanwu.channel.common.enums.TradeStatusEnum;
import com.wanwu.channel.common.exception.SystemException;
import com.wanwu.channel.common.util.DateUtils;
import com.wanwu.channel.common.util.IPUtil;
import com.wanwu.channel.common.util.TrueFalse;
import com.wanwu.channel.converter.PayStatusConvert;
import com.wanwu.channel.core.tool.AlarmPoolUtil;
import com.wanwu.channel.dao.entity.ChannelMerchantInfoEntity;
import com.wanwu.channel.dto.vo.PayQueryStrategyReqVo;
import com.wanwu.channel.dto.vo.PayQueryStrategyRespVo;
import com.wanwu.channel.dto.vo.PrepayStrategyReqVo;
import com.wanwu.channel.remote.wxpay.config.WeixinGlobalConfig;
import com.wanwu.channel.remote.wxpay.http.WechatHttp;
import com.wanwu.channel.remote.wxpay.util.WXPayUtil;
import com.wanwu.channel.remote.wxpay.util.WechatSignUtil;
import com.wanwu.channel.service.strategy.domain.PrepayStrategyResponse;
import com.wanwu.channel.tools.DingAlarmTool;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.net.URLEncoder;
import java.util.Date;

@Component
public class WeixinGlobalStrategy implements PayStrategy {

    private static final Logger logger = LoggerFactory.getLogger(WeixinGlobalStrategy.class);

    @Resource
    private WechatHttp wechatHttp;

    @Resource
    private WeixinGlobalConfig weixinGlobalConfig;

    @Resource
    private DingAlarmTool dingAlarmTool;

    @Resource
    private AlarmPoolUtil alarmPoolUtil;


    @Value("${mq.ding.appKey}")
    private String dingKey;

    @Override
    public PrepayStrategyResponse generatePayParams(PayType payType, PrepayStrategyReqVo req) {
        ChannelMerchantInfoEntity entity = req.getChannelMerchantInfoEntity();
        WechatHttp.PrepayReq prepayReq = new WechatHttp.PrepayReq();
        prepayReq.setChannelMerchantInfoEntity(entity);
        prepayReq.setAppId(null == entity ? req.getAppId() : entity.getMerchantAppId());
        prepayReq.setMchId(null == entity ? req.getCusId() : entity.getMerchantNo());
        prepayReq.setBody(req.getOrderName());
        prepayReq.setOutTradeNo(req.getChannelNo());
        prepayReq.setTotalFee(req.getPayAmount().intValue());
        //订单过期时间：十分钟
        Date expireTime = new Date(req.getPayOrderCreateTime().getTime() + (10 * 60 * 1000));
        prepayReq.setTimeStart(DateUtils.get(8, req.getPayOrderCreateTime()));
        prepayReq.setTimeExpire(DateUtils.get(8, expireTime));

        prepayReq.setAttach(req.getAttach());
        if (PayType.WECHAT_APP == payType) {
            prepayReq.setTradeType("APP");
            prepayReq.setSpbillCreateIp(IPUtil.firstIp());
        } else if (PayType.WECHAT_H5 == payType) {
            prepayReq.setTradeType("MWEB");
            prepayReq.setSpbillCreateIp(req.getSpbillCreateIp());
        } else {
            //小程序
            prepayReq.setTradeType("JSAPI");
            prepayReq.setOpenId(req.getAcct());
            prepayReq.setSpbillCreateIp(IPUtil.firstIp());
        }
        PrepayStrategyResponse response = new PrepayStrategyResponse();
        String notifyUrl = weixinGlobalConfig.getNotifyUrl();
        if (null != entity) {
            notifyUrl = notifyUrl + "/" + entity.getPayChannel() + "/" + entity.getBizCode() + "/" + entity.getMerchantNo();
        }
        prepayReq.setNotifyUrl(notifyUrl);
        try {
            WechatHttp.PrepayResp prepayResp = wechatHttp.prepay(prepayReq);
            if (TrueFalse.UPPER_SUCCESS.equals(prepayResp.getReturnCode())) {
                if (TrueFalse.UPPER_SUCCESS.equals(prepayResp.getResultCode())) {
                    response.setTradeStatus(TradeStatusEnum.SUCCESS);
                    String payInfo = makePayInfo(payType, prepayReq, prepayResp);
                    response.setPrepayOrderString(payInfo);
                    response.setErrorCode(prepayResp.getResultCode());
                    response.setErrorMsg(prepayResp.getReturnMsg());
                    response.setPrepayReq(prepayResp.getReqXml());
                    response.setPrepayResp(prepayResp.getRespXml());
                    if (StringUtils.isNotEmpty(req.getMerPageUrl())) {
                        response.setMWebUrl(prepayResp.getMwebUrl() + "&redirect_url=" + URLEncoder.encode(req.getMerPageUrl(), "UTF-8"));
                    }
                } else {
                    response.setErrorCode(prepayResp.getErrCode());
                    response.setErrorMsg(prepayResp.getErrCodeDes());
                }
            } else {
                response.setErrorCode(prepayResp.getReturnCode());
                response.setErrorMsg(prepayResp.getReturnMsg());
            }
        } catch (Exception e) {
            logger.info("微信统一下单异常：{0}", e);
            response.setTradeStatus(TradeStatusEnum.FAIL);
            if (e instanceof SystemException) {
                SystemException ex = (SystemException) e;
                response.setErrorCode(ex.getCode());
                response.setErrorMsg(ex.getMsg());
            } else {
                response.setErrorCode(ExceptionEnum.E10000.name());
                response.setErrorMsg(ExceptionEnum.E10000.getMsg());
            }
        }
        return response;
    }

    /**
     * 组装微信支付串
     *
     * @return
     */
    private String makePayInfo(PayType payType, WechatHttp.PrepayReq prepayReq, WechatHttp.PrepayResp prepayResp) {
        JSONObject payInfo = new JSONObject();
        //商户平台key
        String key = weixinGlobalConfig.getApiKey();
        if (null != prepayReq.getChannelMerchantInfoEntity()) {
            //兼容使用渠道商户信息表配置逻辑，优先使用表配置的key
            key = prepayReq.getChannelMerchantInfoEntity().getApiKey();
        }
        if (PayType.WECHAT_APP == payType) {
            //app拉起支付串
            payInfo.put("appid", prepayReq.getAppId());
            payInfo.put("partnerid", prepayReq.getMchId());
            payInfo.put("prepayid", prepayResp.getPrepayId());
            payInfo.put("package", "Sign=WXPay");
            payInfo.put("noncestr", WXPayUtil.generateNonceStr());
            payInfo.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000L));
            WechatSignUtil.sign(payInfo, key);
        } else {
            //小程序拉起支付串
            payInfo.put("appId", prepayReq.getAppId());
            payInfo.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000L));
            payInfo.put("nonceStr", WXPayUtil.generateNonceStr());
            payInfo.put("package", "prepay_id=" + prepayResp.getPrepayId());
            payInfo.put("signType", "MD5");
            WechatSignUtil.sign(payInfo, key);
            String sign = payInfo.getString("sign");
            payInfo.put("paySign", sign);
            payInfo.remove("sign");
        }
        return payInfo.toJSONString();
    }

    @Override
    public PayQueryStrategyRespVo queryPayHttp(PayType payType, PayQueryStrategyReqVo request) {
        ChannelMerchantInfoEntity entity = request.getChannelMerchantInfoEntity();
        PayQueryStrategyRespVo response = new PayQueryStrategyRespVo();
        WechatHttp.PayQueryReq payQueryReq = new WechatHttp.PayQueryReq();
        payQueryReq.setChannelMerchantInfoEntity(entity);
        payQueryReq.setOutOrderNo(0 == request.getThirdFlag() ? request.getBizOrderNo() : request.getChannelNo());

        payQueryReq.setAppId(null == entity ? request.getMerchantAppId() : entity.getMerchantAppId());
        payQueryReq.setMchId(null == entity ? request.getMerchantNo() : entity.getMerchantNo());
        WechatHttp.PayQueryResp payQueryResp = wechatHttp.payQuery(payQueryReq);
        if (TrueFalse.UPPER_SUCCESS.equals(payQueryResp.getReturnCode())) {
            if (TrueFalse.UPPER_SUCCESS.equals(payQueryResp.getResultCode())) {
                response.setChannelPayStatus(PayStatusConvert.wechatConvert(payQueryResp.getTradeState()));
                response.setThirdOrderNo(payQueryResp.getTransactionId());
                response.setBizOrderNo(payQueryResp.getOutTradeNo());
                if (TrueFalse.UPPER_SUCCESS.equals(payQueryResp.getTradeState())) {
                    response.setFinishTime(DateUtils.formatDate(8, payQueryResp.getTimeEnd()));
                }
                response.setErrMsg(payQueryResp.getTradeStateDesc());
            } else {
                throw new SystemException(ExceptionEnum.E10006, payQueryResp.getErrCodeDes());
            }
        } else {
            throw new SystemException(ExceptionEnum.E10006, payQueryResp.getReturnMsg());
        }
        return response;
    }

}
